package xin.petstore.framework.web.sitemesh;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import org.sitemesh.builder.BaseSiteMeshBuilder;
import org.sitemesh.config.ObjectFactory;
import org.sitemesh.content.ContentProcessor;
import org.sitemesh.content.tagrules.TagRuleBundle;
import org.w3c.dom.Element;

public class XmlConfigurator {
    private String remoteFilePath;
    private final Xml xml;
    private final ObjectFactory objectFactory;

    public XmlConfigurator(ObjectFactory objectFactory, Element siteMeshElement) {
        this.objectFactory = objectFactory;
        this.xml = new Xml(siteMeshElement);
    }

    public void configureCommon(BaseSiteMeshBuilder builder) {
        String tagRuleBundleName;
        for (Xml tagRuleBundle : this.xml.child("content-processor").children(
                "tag-rule-bundle")) {
            tagRuleBundleName = tagRuleBundle.attribute("class");
            if (tagRuleBundleName != null) {
                builder.addTagRuleBundle(
                        (TagRuleBundle) this.objectFactory
                                .create(tagRuleBundleName));
            }

        }

        String contentProcessorName = this.xml.child("content-processor").attribute(
                "class");
        if (contentProcessorName != null) {
            builder.setCustomContentProcessor(
                    (ContentProcessor) this.objectFactory
                            .create(contentProcessorName));
        }

        for (Xml mapping : this.xml.children("mapping")) {
            List paths = mapping.children("path");
            if (!paths.isEmpty()) {
                for (Xml path : paths) {
                    addDecoratorPaths(builder, mapping, path.text());
                }
            } else {
                addDecoratorPaths(builder, mapping, mapping.attribute("path", "/*"));
            }
        }
    }

    private void addDecoratorPaths(BaseSiteMeshBuilder builder, Xml mapping, String path) {
        List decorators = new ArrayList();
        if (mapping.attribute("decorator") != null) {
            decorators.add(prefile(mapping.attribute("decorator")));
        }
        for (Xml decorator : mapping.children("decorator")) {
            if (decorator.text() != null) {
                decorators.add(prefile(decorator.text()));
            }
        }

        builder.addDecoratorPaths(path, decorators);
    }

    protected ObjectFactory getObjectFactory() {
        return this.objectFactory;
    }

    private String prefile(String url) {
        if ((url.startsWith("http://")) || (url.startsWith("https://"))) {
            String fileName = url.substring(url.lastIndexOf("/"));
            String p = url.split("//")[1];
            p = p.substring(p.indexOf("/") + 1, p.lastIndexOf("/"));
            download(url, fileName, this.remoteFilePath + p);
            url = p + fileName;
        }
        return url;
    }

    public void download(String urlString, String filename, String savePath) {
        InputStream is = null;
        OutputStream os = null;
        try {
            URL url = new URL(urlString);
            URLConnection con = url.openConnection();
            con.setConnectTimeout(5000);
            is = con.getInputStream();

            byte[] bs = new byte[1024];

            File sf = new File(savePath);
            if (!sf.exists()) {
                sf.mkdirs();
            }
            os = new FileOutputStream(sf.getPath() + File.pathSeparator +
                    filename);
            int len;
            while ((len = is.read(bs)) != -1) {
                os.write(bs, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();

            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null)
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void setRemoteFilePath(String remoteFilePath) {
        this.remoteFilePath = remoteFilePath;
    }
}
